package cn.com.chengmandian.bike.service.impl;

import cn.com.chengmandian.agent.utils.AuthUtil;
import cn.com.chengmandian.bike.mapper.EbMemberWalletMapper;
import cn.com.chengmandian.bike.model.*;
import cn.com.chengmandian.bike.model.vo.AgentPayInfo;
import cn.com.chengmandian.bike.service.*;
import cn.com.chengmandian.bike.utils.AliPayUtil;
import cn.com.chengmandian.bike.utils.WxPayUtil;
import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.AgentInfo;
import cn.com.chengmandian.core.web.pojo.AjaxResult;
import cn.com.chengmandian.core.web.utils.LocalMapUtil;
import cn.com.chengmandian.service.bike.BikePayClient;
import cn.com.chengmandian.service.bike.constants.*;
import cn.com.chengmandian.service.bike.form.BikeRefundForm;
import cn.com.chengmandian.service.bike.form.WalletBalanceRefundForm;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 电单车运营-用户钱包 服务实现类
 * </p>
 *
 * @author AutoGenerator
 * @since 2021-12-08
 */
@Slf4j
@Service
public class EbMemberWalletServiceImpl extends ServiceImpl<EbMemberWalletMapper, EbMemberWallet> implements IEbMemberWalletService {

    @Autowired
    private EbMemberWalletMapper memberWalletMapper;

    @Autowired
    private IEbMemberPayService memberPayService;

    @Autowired
    private IEbMemberMoneyService memberMoneyService;

    @Autowired
    private IEbMemberInfoService memberInfoService;

    @Autowired
    private IEbRefundInfoService refundInfoService;

    @Autowired
    private IEbMessageInfoService messageInfoService;

    @Autowired
    private IEbAgentInfoService agentInfoService;

    @Autowired
    private IEbPayAccountService payAccountService;

    @Autowired
    private BikePayClient bikePayClient;

    @Override
    public EbMemberWallet getMemberWallet(Integer memberId) {
        EbMemberWallet memberWallet = this.getOne(new LambdaQueryWrapper<EbMemberWallet>().eq(EbMemberWallet::getMemberId, memberId).last("limit 1"));
        if (memberWallet == null) {
            memberWallet = new EbMemberWallet();
            memberWallet.setMemberId(memberId);
            memberWallet.setMoney(new BigDecimal(0.00));
            memberWallet.setGiftMoney(new BigDecimal(0.00));
            memberWallet.setChargeMoney(new BigDecimal(0.00));
            this.save(memberWallet);
        }
        return memberWallet;
    }

    @Override
    @Transactional
    public void updateBalanceForBoth(Integer areaId, Integer memberId, BigDecimal chargeMoney, BigDecimal giftMoney, MemberMoneyBusinessTypeEnum businessType, Integer businessId, MemberMoneyOperationTypeEnum operationType) {
        if (chargeMoney != null && chargeMoney.compareTo(new BigDecimal(0)) > 0) {
            memberMoneyService.createCharge(areaId, memberId, businessType, businessId, operationType, chargeMoney);
            memberWalletMapper.updateCharge(memberId, businessType.getInout().equals(CommonConstant.ZERO) ? chargeMoney.negate() : chargeMoney);
        }
        if (giftMoney != null && giftMoney.compareTo(new BigDecimal(0)) > 0) {
            memberMoneyService.createGift(areaId, memberId, businessType, businessId, operationType, giftMoney);
            memberWalletMapper.updateGift(memberId, businessType.getInout().equals(CommonConstant.ZERO) ? giftMoney.negate() : giftMoney);
        }
    }

    @Override
    public void refundMoney(Integer areaId, Integer memberId, MemberMoneyBusinessTypeEnum businessType, Integer businessId,  BigDecimal payChargeMoney, BigDecimal payGiftMoney) {
        memberWalletMapper.refundUpdateMoney(memberId,payChargeMoney,payGiftMoney);
        if (payChargeMoney != null && payChargeMoney.compareTo(new BigDecimal(0)) > 0) {
            memberMoneyService.createCharge(areaId, memberId, businessType, businessId, MemberMoneyOperationTypeEnum.SERVICE, payChargeMoney);
        }
        if (payGiftMoney != null && payGiftMoney.compareTo(new BigDecimal(0)) > 0) {
            memberMoneyService.createCharge(areaId, memberId, businessType, businessId, MemberMoneyOperationTypeEnum.SERVICE, payGiftMoney);
        }
    }

    @Override
    @Transactional
    public void walletBalanceRefund(WalletBalanceRefundForm form) {
        // 查询一年内可退款充值记录
        List<EbMemberPay> memberPayList = memberPayService.getYearPayRecord(form.getMemberId());
        Assert.isTrue(ArrayUtil.isAllNotEmpty(memberPayList),"一年内未有钱包充值记录!");
        BigDecimal payMoney = memberPayList.stream().map(EbMemberPay::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
        payMoney = payMoney.subtract(memberPayList.stream().filter(item -> ObjectUtil.isNotNull(item.getRefundMoney())).map(EbMemberPay::getRefundMoney).reduce(BigDecimal.ZERO,BigDecimal::add));
        Assert.isTrue(form.getRefundMoney().compareTo(payMoney) <= 0,"退款金额超出一年内钱包充值金额总和!");
        // 钱包余额
        EbMemberWallet ebMemberWallet = this.getMemberWallet(form.getMemberId());
        Assert.isTrue(form.getRefundMoney().compareTo(ebMemberWallet.getChargeMoney()) <= 0,"退款金额超出钱包充值余额!");
        BigDecimal refundMoney = form.getRefundMoney();
        // 循环支付记录退款余额
        for(EbMemberPay ebMemberPay : memberPayList){
            // 退完终止退款
            if(refundMoney.compareTo(BigDecimal.ZERO) <= 0) continue;
            // 可退款金额
            BigDecimal canRefundMoney = ebMemberPay.getMoney().subtract(ObjectUtil.isNull(ebMemberPay.getRefundMoney()) ? BigDecimal.ZERO : ebMemberPay.getRefundMoney());
            if(canRefundMoney.compareTo(BigDecimal.ZERO) <= 0 ) continue;
            if(canRefundMoney.compareTo(refundMoney) >= 0){
                canRefundMoney = refundMoney;
                refundMoney = BigDecimal.ZERO;
            }else{
                refundMoney = refundMoney.subtract(canRefundMoney);
            }
            log.info("单号:{},可退款金额:{}",ebMemberPay.getPayNo(),canRefundMoney);
            AgentInfo agentInfo = LocalMapUtil.getAgentInfo();

            RefundChannelEnum refundChannel = null;
            if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
                refundChannel = RefundChannelEnum.WX;
            } else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
                refundChannel = RefundChannelEnum.ALI;
            }

            // 生成退款支付记录
            EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),ebMemberPay.getMemberId(), ebMemberPay.getId(), ebMemberPay.getId(), ebMemberPay.getFeeRatio(), canRefundMoney, RefundBusinessTypeEnum.MONEY, refundChannel, form.getRemark(),form.getLoginUser(),JSONObject.toJSONString(form));
            EbMemberInfo ebMemberInfo = memberInfoService.getById(form.getMemberId());

            EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
            if (info.getPayAccountId() != null) {
                EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), ebMemberInfo.getId());
                if (payAccount != null) {
                    BikeRefundForm refundForm = new BikeRefundForm();
                    refundForm.setBusinessType(RefundBusinessTypeEnum.MONEY);
                    refundForm.setMemberPayId(ebMemberPay.getId());
                    refundForm.setMoney(ebRefundInfo.getMoney());
                    refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                    refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                    refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                    AjaxResult result = bikePayClient.refund(ebMemberPay.getAgentId(), refundForm);
                    Assert.isTrue(result.isSuccess(), result.getMessage());
                    continue;
                }
            }

            String notifyUrl = "http://"+ agentInfo.getDomain()+ "/api/v1/bikeuser/notify";
            if (ebMemberPay.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
                try {
                    Map<String, String> res =  AliPayUtil.getTradeRefundRequestParam(
                            agentInfo.getAliMiniAppid(),
                            ebMemberInfo.getAlipayUserId(),
                            ebMemberInfo.getAlipayOpenId(),
                            "充值余额退款",
                            ebMemberPay.getPayNo(),
                            ebRefundInfo.getRefundNo(),
                            ebRefundInfo.getMoney(),
                            agentInfo.getAliPayPrivateKey(),
                            agentInfo.getAliPayCertPath(),
                            agentInfo.getAliPayPublicCertPath(),
                            agentInfo.getAliPayRootCertPath());
                    ebRefundInfo.setChannelNo(res.get("trade_no"));
                    this.walletRefundSuccess(ebRefundInfo, ebMemberPay.getPayNo());
                } catch (Exception ex) {
                    log.error("支付宝退款失败", ex);
                    throw new BadResponseException("支付宝退款失败:" + ex.getMessage());
                }
            }else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
                try {
                    WxPayUtil.refund(
                            agentInfo.getWxMchId(),
                            ebRefundInfo.getRefundNo(),
                            ebMemberPay.getPayNo(),
                            "充值余额退款",
                            ebRefundInfo.getMoney(),
                            ebMemberPay.getMoney(),
                            agentInfo.getWxKeyPath(),
                            agentInfo.getWxCertPath(),
                            notifyUrl + "/wx/wallet/refund/" + LocalMapUtil.getAgentInfo().getId());
                } catch (Exception ex) {
                    log.error("微信退款失败", ex);
                    throw new BadResponseException("微信退款失败:" + ex.getMessage());
                }
            }
        }
    }

    @Override
    public void walletRefundSuccess(EbRefundInfo ebRefundInfo, String payNo) {
        // 支付记录
        EbMemberPay ebMemberPay = memberPayService.getByNo(payNo);
        log.info("支付记录(余额退款成功):{}",ObjectUtil.isNull(ebMemberPay) ? null : JSONObject.toJSONString(ebMemberPay));
        if(ObjectUtil.isNull(ebMemberPay)) return;
        MemberPayStatusEnum memberPayStatusEnum = MemberPayStatusEnum.PAID;
        // 实际退款金额
        BigDecimal refundMoney = ebRefundInfo.getRefundMoney().add(ObjectUtil.isNull(ebMemberPay.getRefundMoney()) ? BigDecimal.ZERO : ebMemberPay.getRefundMoney());
        if(refundMoney.compareTo(ebMemberPay.getMoney()) >= 0){
            memberPayStatusEnum = MemberPayStatusEnum.REFUND;
        }
        // 更新充值记录
        memberPayService.update(new LambdaUpdateWrapper<EbMemberPay>()
                .set(EbMemberPay::getRefundMoney,refundMoney)
                .set(EbMemberPay::getRefundTime,DateUtil.date())
                .set(EbMemberPay::getStatus,memberPayStatusEnum.getCode())
                .eq(EbMemberPay::getId,ebMemberPay.getId()));
        // 更新余额
        EbMemberWallet ebMemberWallet = this.getMemberWallet(ebRefundInfo.getMemberId());

        // 实际充值余额
        BigDecimal chargeMoney = ebMemberWallet.getChargeMoney().subtract(ebRefundInfo.getRefundMoney());
        // 实际总余额
        BigDecimal money = ebMemberWallet.getMoney().subtract(ebRefundInfo.getRefundMoney());
        this.update(new LambdaUpdateWrapper<EbMemberWallet>()
                .set(EbMemberWallet::getChargeMoney,chargeMoney)
                .set(EbMemberWallet::getMoney,money)
                .eq(EbMemberWallet::getId,ebMemberWallet.getId()));
        // 退款信息
        refundInfoService.update(new LambdaUpdateWrapper<EbRefundInfo>()
                .set(EbRefundInfo::getStatus,RefundStatusEnum.REFUND_OK.getCode())
                .set(EbRefundInfo::getCompleteTime,DateUtil.date())
                .eq(EbRefundInfo::getId,ebRefundInfo.getId()));
        messageInfoService.addSys(ebMemberPay.getMemberId(), MessageChannelEnum.SYS,
                "尊敬的用户您好，你的钱包充值金额已退款"+ebRefundInfo.getRefundMoney()+"元，当前余额"+money+"元。",
                null, MessageBusinessTypeEnum.WALLET, null);
    }

    @Override
    @Transactional
    public void updateBalance(Integer areaId, Integer memberId, BigDecimal money, MemberMoneyBusinessTypeEnum businessType, Integer businessId, MemberMoneyOperationTypeEnum operationType) {
        // 赠送金额
        if (businessType == MemberMoneyBusinessTypeEnum.ADD_GIFT) {
            memberMoneyService.createGift(areaId, memberId, businessType, businessId, operationType, money);
            memberWalletMapper.updateGift(memberId, businessType.getInout().equals(CommonConstant.ZERO) ? money.negate() : money);
            // 充值金额
        } else if (businessType == MemberMoneyBusinessTypeEnum.CHARGE ||
                businessType == MemberMoneyBusinessTypeEnum.CARD_COST ||
                businessType == MemberMoneyBusinessTypeEnum.PAY_DEPOSIT ||
                businessType == MemberMoneyBusinessTypeEnum.PAY_DEPOSIT_CARD) {
            memberMoneyService.createCharge(areaId, memberId, businessType, businessId, operationType, money);
            memberWalletMapper.updateCharge(memberId, businessType.getInout().equals(CommonConstant.ZERO) ? money.negate() : money);
            // 骑行消费，双边消费
        }
    }

    /**
     * 钱包支付骑行订单
     * @param rideOrder
     * @return
     */
    public boolean payForRideOrder(EbRideOrder rideOrder) {
        EbMemberWallet memberWallet = this.getMemberWallet(rideOrder.getMemberId());
        // 余额不足，暂不支付
        if (memberWallet.getMoney().compareTo(rideOrder.getMoney()) < 0) {
            return false;
        }
        // 创建支付订单
        EbMemberPay memberPay = memberPayService.createPay(rideOrder.getAreaId(), rideOrder.getMemberId(), MemberPayBusinessTypeEnum.RIDE_ORDER_PAY, rideOrder.getId(),
                rideOrder.getMoney(), PayChannelEnum.WALLET.getCode());
        memberPayService.paySuccessByPay(memberPay, null);
        return true;
    }
}
